package com.test.learnopenglandroid;

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import org.apache.commons.math3.linear.ArrayRealVector;
import org.apache.commons.math3.linear.RealVector;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;


/**
 * 创建一个光照场景
 * */
public abstract class RenderWithLookControl implements GLSurfaceView.Renderer {

    protected float[] mModelMatrix = new float[16];//4x4
    protected float[] mViewMatrix = new float[16];//4x4
    protected float[] mProjectionMatrix = new float[16];

    protected RealVector cameraPos = new ArrayRealVector(new double[]{0.0f, 0.0f,  3.0f});
    protected RealVector cameraFront =new ArrayRealVector(new double[]{0.0f, 0.0f, -1.0f});
    protected final RealVector cameraUp =new ArrayRealVector(new double[]{0.0f, 1.0f, 0.0f});

    protected double cameraSpeed = 0.5f;
    protected double yaw=-90;
    protected double pitch=0;

    protected Context mContext;

    public RenderWithLookControl(Context context){
        mContext = context;
    }

    public void updateFront(){
        if(pitch > 89.0f)
            pitch =  89.0f;
        if(pitch < -89.0f)
            pitch = -89.0f;
        synchronized (cameraPos) {
            cameraFront.setEntry(0, Math.cos(Math.toRadians(pitch)) * Math.cos(Math.toRadians(yaw)));
            cameraFront.setEntry(1, Math.sin(Math.toRadians(pitch)));
            cameraFront.setEntry(2, Math.cos(Math.toRadians(pitch)) * Math.sin(Math.toRadians(yaw)));
            cameraFront = cameraFront.unitVector();
        }
        Log.d("yhy",yaw+" "+pitch+" "+cameraFront.toString());
    }

    public void addCameraControlIntoView(ViewGroup keyPadRootView,View touchView){
        LayoutInflater.from(keyPadRootView.getContext()).inflate(R.layout.keypad_layout, keyPadRootView);
        keyPadRootView.findViewById(R.id.buttonUp).setOnClickListener(mKeypadClick);
        keyPadRootView.findViewById(R.id.buttonDown).setOnClickListener(mKeypadClick);
        keyPadRootView.findViewById(R.id.buttonLeft).setOnClickListener(mKeypadClick);
        keyPadRootView.findViewById(R.id.buttonRight).setOnClickListener(mKeypadClick);
        touchView.setOnTouchListener(mYawPitchTouch);
    }

    private View.OnTouchListener mYawPitchTouch = new View.OnTouchListener(){

        public boolean firstMouse = false;
        public float lastY;
        public float lastX;

        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            Log.d("yhy",motionEvent.toString());

            switch (motionEvent.getAction()){
                case MotionEvent.ACTION_MOVE:

                    float xpos = motionEvent.getRawX();
                    float ypos = motionEvent.getRawY();
                    Log.d("yhy",xpos+" "+ypos);

                    if(firstMouse)
                    {
                        lastX = xpos;
                        lastY = ypos;
                        firstMouse = false;
                        break;
                    }

                    float xoffset = xpos - lastX;
                    float yoffset = lastY - ypos;
                    lastX = xpos;
                    lastY = ypos;

                    float sensitivity = 0.05f;
                    xoffset *= sensitivity;
                    yoffset *= sensitivity;

                    yaw   += xoffset;
                    pitch += yoffset;
                    updateFront();
                    break;
                case MotionEvent.ACTION_DOWN:
                    firstMouse = true;
                    break;
            }
            return true;
        }
    };

    private View.OnClickListener mKeypadClick = new View.OnClickListener(){

        @Override
        public void onClick(View view) {
            synchronized (cameraPos) {
                switch (view.getId()) {
                    case R.id.buttonUp:
                        cameraPos = cameraPos.add(cameraFront.mapMultiply(cameraSpeed));
                        break;

                    case R.id.buttonDown:
                        cameraPos = cameraPos.subtract(cameraFront.mapMultiply(cameraSpeed));
                        break;
                    case R.id.buttonRight:
                        RealVector rightVec = VectorMatrixHelper.crossProduct(cameraFront, cameraUp).mapMultiply(cameraSpeed);
                        rightVec = rightVec.unitVector();
                        cameraPos = cameraPos.add(rightVec);
                        break;
                    case R.id.buttonLeft:
                        RealVector leftVec
                                = VectorMatrixHelper.crossProduct(cameraFront, cameraUp).mapMultiply(cameraSpeed);
                        leftVec = leftVec.unitVector();
                        cameraPos = cameraPos.subtract(leftVec);
                        break;
                }
            }
        }
    };

    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {

        //createShaderProgram();
        //initVBO
        //initTexture
    }


    /**
     * 模型的View矩阵
     * */
    protected void updateCameraViewMatrix() {
        synchronized (cameraPos) {
            float camX = (float) cameraPos.getEntry(0);
            float camY = (float) cameraPos.getEntry(1);
            float camZ = (float) cameraPos.getEntry(2);
            RealVector cameraCenter = cameraPos.add(cameraFront);
            float centerX = (float) cameraCenter.getEntry(0);
            float centerY = (float) cameraCenter.getEntry(1);
            float centerZ = (float) cameraCenter.getEntry(2);

            Matrix.setIdentityM(mViewMatrix, 0);
            /**
             * view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
             * */
            Matrix.setLookAtM(mViewMatrix, 0,
                    camX, camY, camZ,
                    centerX, centerY, centerZ,
                    0.0f, 1.0f, 0.0f
            );
        }
    }

    protected  void updateProjectionMatrix(){
        float ratio = (float) mScreenW / (float) mScreenH;
        Matrix.perspectiveM(mProjectionMatrix,0,45f,ratio,0.1f,100f);
    }

    protected int mScreenW = 0;
    protected int mScreenH = 0;
    @Override
    public void onSurfaceChanged(GL10 gl10, int width, int height) {
        Log.d("yhy", "onSurfaceChanged" + width + " " + height);
        mScreenW = width;
        mScreenH = height;
        GLES20.glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl10) {
        GLES20.glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        //如果你启用了深度缓冲，你还应该在每个渲染迭代之前使用GL_DEPTH_BUFFER_BIT来清除深度缓冲，否则你会仍在使用上一次渲染迭代中的写入的深度值：
        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
        updateCameraViewMatrix();
        updateProjectionMatrix();
        //draw arrays here
        renderDraw();
    }

    protected abstract void renderDraw();
}
